# coding: utf-8

import datetime

from django.db.models.signals import post_save, pre_save
from django.dispatch import receiver

from . import models

# from main.apps.op_log.utils import oplog_utils
# from .models import PurifyConfig


class OpLogUtils(object):
    """
    reference: https://github.com/jjkester/django-auditlog/blob/master/src/auditlog/diff.py
    """

    def model_instance_changes(self, instance, log_fields=None, is_delete=False,
                               exclude_fields=None):
        model = instance.__class__
        old_instance = model.objects.filter(id=instance.id).first()
        if is_delete:
            diff = self.model_instance_diff(old_instance, None, log_fields, exclude_fields)
        else:
            diff = self.model_instance_diff(old_instance, instance, log_fields, exclude_fields)
        return diff

    def get_field_value(self, obj, field):
        value = getattr(obj, field.name, None)
        if not value:
            return '空'

        if isinstance(value, datetime.datetime) or isinstance(value, datetime.date):
            return value.strftime('%Y-%m-%d %H:%M:%S')

        choices_display_value = getattr(obj, 'get_%s_display' % field.name, None)
        if choices_display_value is not None:
            return choices_display_value()

        return value

    def model_instance_diff(self, old, new, log_fields=None, exclude_fields=None):
        if old is None and new is not None:
            action = 'add'
            model_fields = new._meta.fields
        elif new is None and old is not None:
            action = 'delete'
            model_fields = old._meta.fields
        else:
            action = 'edit'
            model_fields = new._meta.fields

        change_msg_list = []

        for field in model_fields:
            if log_fields is not None and field.attname not in log_fields:
                continue
            if exclude_fields is not None and field.attname in exclude_fields:
                continue
            field_verbose_name = field.verbose_name

            old_value = self.get_field_value(old, field)
            new_value = self.get_field_value(new, field)

            if old_value != new_value:
                if action == 'add':
                    change_msg = '{field_name}：{new_value}'.format(
                        field_name=field_verbose_name,
                        new_value=new_value,
                    )
                elif action == 'edit':
                    change_msg = '{field_name}：{old_value} -> {new_value}'.format(
                        field_name=field_verbose_name,
                        old_value=old_value,
                        new_value=new_value,
                    )
                else:
                    change_msg = '{field_name}：{old_value}'.format(
                        field_name=field_verbose_name,
                        old_value=old_value,
                    )
                change_msg_list.append(change_msg)

        if not change_msg_list:
            return None

        change_msgs = '，'.join(change_msg_list)
        return change_msgs

    def save_op_log(
            self,
            instance,
            object_type,
            log='',
            log_type='',
            log_fields=None,
            is_delete=False,
            exclude_fields=None,
            object_id=None):

        object_id = object_id or instance.id
        if not log:
            log = self.model_instance_changes(instance, log_fields, is_delete, exclude_fields)

        if log is None:
            return None

        op_log = models.OpLog.objects.create(
            object_id=object_id,
            object_type=object_type,
            log_type=log_type,
            log=log,
        )
        return op_log

    def bulk_save_op_log(self, object_ids, object_type, log='', log_type=''):
        if not log:
            return None

        for object_id in object_ids:
            models.OpLog.objects.create(
                object_id=object_id,
                object_type=object_type,
                log_type=log_type,
                log=log,
            )
        return object_ids

    def save_oid_op_log(self, object_id, object_type, log='', log_type=''):
        if not log:
            return None
        op_log = models.OpLog.objects.create(
            object_id=object_id,
            object_type=object_type,
            log_type=log_type,
            log=log,
        )
        return op_log


oplog_utils = OpLogUtils()


def create_save_log_signal(model):
    @receiver(signal=[post_save, pre_save], sender=model)
    def save_log(sender, instance, **kwargs):
        if instance._state.adding:
            return False
        object_type = getattr(instance, 'object_type', '')
        model_name = model._meta.verbose_name
        if kwargs.get('created'):
            log = oplog_utils.model_instance_diff(None, instance)
            oplog_utils.save_op_log(instance, object_type, log, f'创建{model_name}')
        else:
            log = oplog_utils.model_instance_changes(instance)
            oplog_utils.save_op_log(instance, object_type, log, f'修改{model_name}')

    return save_log
